/*
RNAvigator is a tool for visualizing secondary structure of RNA
Copyright 2012 Elias la Cour & Peter Bertelsen

This file is part of RNAvigator.

RNAvigator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

RNAvigator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with RNAvigator.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package rnavigator.model;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author Elias la Cour & Peter Bertelsen
 */
/**
 * File format examples ============================================================================
 * Example column of the *.ct format:
 *1	A	0	2	0	1
 *
 * Example column of Dot bracket format - *.dbf:
 * UUAGCUCGCCAGUUAGCGAGGUCUGUCCCCACACGACAGAUAAUCGGGUGCAACUCCCGCCCCUUUUCCGAGGGUCAUCGGAACCA
 * ::::(((((::::::))))):((((((:::::::))))))::::((((:::::::))))(((:::[[[[[[))):::]]]]]]:::
 *
 * Example column of Base pair sequence - *.bpseq:
 *  1 G 117 
 *
 * Example column of Shape format *.rp:
 * 1 57	0.8901 
 * 
 *==================================================================================================
 *
 */
// NB ser ud til at *.ct formatet også findes med kun 6 kolonner (se RNA samples mappen i JVIZ for et eksempel)
// Load file skal kaldes fra JfileChooser med en "File file" 
// Flow: load file -> decide from *.ext which method is called -> touppercase -> regex val -> regex split
public class LoadFile {
    
    // Regex patterns for the respective formats (some not used)
//    private static Pattern ctSplitPattern = Pattern.compile("[\\s]+");
//    private static Pattern ctValidatePattern = Pattern.compile("[\\s]+");
//    private static Pattern bpseqSplitPattern = Pattern.compile("[\\s]+");
//    private static Pattern bpseqValidatePattern = Pattern.compile("[\\s]+");
//    private static Pattern dbfValidatePattern = Pattern.compile("(?<=\\G.{1})");
    private static Pattern dbfSplitPattern = Pattern.compile("(?<=\\G.{1})");

    
    
    private File file;
    private static String header = "";
    private String[] baseSequence;
    private String[] knotSequence;
    private double[] shapeReactivity;
    private Structure structure;

    /**
     * 
     * @param file
     * @throws IOException
     */
    public LoadFile(File file) throws IOException {
        this.file = file;
        decideExtension();
    }

    /**
     * 
     * @throws IOException
     */
    public void decideExtension() throws IOException {
        Pattern splitPattern = Pattern.compile("\\."); //"//w"
        String[] result = splitPattern.split(file.getName());
        int length = result.length;
        String extension = result[result.length - 1];
        extension = extension.toLowerCase();

        if (extension.equals("bpseq")) {
            createBPSEQ();
        } else if (extension.equals("ct")) {
            createCT();
        } else if (extension.equals("dbf")) {
            createDotBracket();
        } else if (extension.equals("rp")) {
            createRP();
        } else {
            throw new IOException();

        }

    }

    /**
     * 
     * @return
     */
    public Structure getStructure() {
        structure = new Structure();
        structure.setFilename(file.getName());
        structure.setHeader(header);
        structure.setBaseSequence(baseSequence);
        structure.setDotSequence(knotSequence);
        structure.setShapeReactivity(shapeReactivity);
        return structure;
    }

    /**
     * 
     * @param structure
     * @return
     * @throws IOException
     */
    public Structure getReactivityStructure(Structure structure) throws IOException {
        //for testing purposes only
        if (structure.getBaseSequence().length != shapeReactivity.length) {
            System.out.println("mismatch arraysizes adding nucleotides B in all fields");
            baseSequence = new String[shapeReactivity.length];
            for (int i = 0; i < baseSequence.length; i++) {
                baseSequence[i] = "B";
            }
            structure.setBaseSequence(baseSequence);
        }
        //if(structure.getBaseSequence().length!=shapeReactivity.length)throw new IOException();
        //structure.setDotSequence(knotSequence);
        structure.setShapeReactivity(shapeReactivity);
        return structure;
    }

    /**
     *  \d          A digit: [0-9]
     *  \s          A whitespace character
     *  +           The preceding is repeated one or more times.
     *  [a-zA-Z]    a through z or A through Z. 
     * 
     *  \\w+        This regex will match one or more word character [a-zA-Z_0-9]. This will match any character 
     *              from a to z or A to Z, an underscore, or any single digit from 0 to 9
     * 
     */
    public void createBPSEQ() {
        String s;
        try {
            // brCount is used to decide how big array should be
            BufferedReader brCount = new BufferedReader(new FileReader(file));
            int arraySize = 0;

            String bpseqRegex = "\\d+\\s+[A-Za-z]\\s+\\d+";
            Pattern BPSEQpattern = Pattern.compile(bpseqRegex);
            while ((s = brCount.readLine()) != null) {
                Matcher BPSEQmatcher = BPSEQpattern.matcher(s);
                if (BPSEQmatcher.find()) {
                    ++arraySize;
                }
            }
            baseSequence = new String[arraySize];
            knotSequence = new String[arraySize];
            // br is used to read data into array
            BufferedReader br = new BufferedReader(new FileReader(file));
            header = br.readLine();

            while ((s = br.readLine()) != null) {
                if (validateBPSEQ(s)) {
                    Pattern pattern = Pattern.compile("\\w+");
                    Matcher matcher = pattern.matcher(s);
                    matcher.find();
                    int indexNuc1Knot = Integer.parseInt(matcher.group());
                    matcher.find();
                    String base = matcher.group();
                    base = base.toUpperCase(); //make it upperCase
                    matcher.find();
                    int indexNuc2Knot = Integer.parseInt(matcher.group());

                    baseSequence[indexNuc1Knot - 1] = base;

                    if (indexNuc2Knot == 0) {
                        knotSequence[indexNuc1Knot - 1] = ":";
                    }
                    if (indexNuc1Knot < indexNuc2Knot) {
                        knotSequence[indexNuc1Knot - 1] = "(";
                        knotSequence[indexNuc2Knot - 1] = ")";
                    }
                } else {
                    //if validation fails
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(LoadFile.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Error: " + ex.getMessage());
        }
    }

    /**
     *  \d          A digit: [0-9]
     *  \s          A whitespace character
     *  +           The preceding is repeated one or more times.
     *  [a-zA-Z]    a through z or A through Z. 
     * 
     *  \\w+        This regex will match one or more word character [a-zA-Z_0-9]. This will match any character 
     *              from a to z or A to Z, an underscore, or any single digit from 0 to 9
     * 
     */
    public void createCT() {
        String s;
        try {
            // brCount is used to decide how big array should be
            BufferedReader brCount = new BufferedReader(new FileReader(file));
            int arraySize = 0;
            String ctRegex = "\\d+\\s+[A-Za-z]\\s+\\d+\\s+\\d+\\s+\\d+";
            Pattern CTpattern = Pattern.compile(ctRegex);
            while ((s = brCount.readLine()) != null) {
                Matcher CTmatcher = CTpattern.matcher(s);
                if (CTmatcher.find()) {
                    ++arraySize;
                }
            }
            baseSequence = new String[arraySize];
            knotSequence = new String[arraySize];
            // br is used to read data into array
            BufferedReader br = new BufferedReader(new FileReader(file));
            header = br.readLine();
            System.out.println(header);
            int counter = 0;
            while ((s = br.readLine()) != null) {
                if (validateCT(s)) {
                    Pattern pattern = Pattern.compile("\\w+");
                    Matcher matcher = pattern.matcher(s);
                    matcher.find();
                    int indexNuc1Knot = Integer.parseInt(matcher.group());
                    matcher.find();
                    String base = matcher.group();
                    base = base.toUpperCase(); //make it upperCase
                    matcher.find();
                    matcher.find();
                    matcher.find();
                    int indexNuc2Knot = Integer.parseInt(matcher.group());
                    baseSequence[indexNuc1Knot - 1] = base;
                    if (indexNuc2Knot == 0) {
                        knotSequence[indexNuc1Knot - 1] = ":";
                    }
                    if (indexNuc1Knot < indexNuc2Knot) {
                        knotSequence[indexNuc1Knot - 1] = "(";
                        knotSequence[indexNuc2Knot - 1] = ")";
                    }
                } else {
                    //if validation fails
                }
            }

        } catch (Exception ex) {
            Logger.getLogger(LoadFile.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Error in inputfile: " + ex.getMessage());
        }
    }

    /**
     * 
     */
    public void createDotBracket() {
        String s;
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            header = br.readLine();
            while ((s = br.readLine()) != null) {
                if (validateDotbracket(s)) {

                    Pattern splitPattern = dbfSplitPattern;
                    Pattern matchPattern = Pattern.compile("[A-Z]");
                    Matcher m = matchPattern.matcher(s);
                    // If the input string contain any characters [A-Z]
                    if (m.lookingAt()) {
                        String[] result = splitPattern.split(s);
                        //makes all letters uppercase
                        for (int i = 0; i < result.length; i++) {
                            result[i] = result[i].toUpperCase();
                        }
                        baseSequence = result;
                    } else {
                        String[] result = splitPattern.split(s);
                        knotSequence = result;
                    }
                } else {
                    //if validation fails
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(LoadFile.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Error: " + ex.getMessage());
        }
    }

    /**
     *  \d          A digit: [0-9]
     *  \s          A whitespace character
     *  +           The preceding is repeated one or more times.
     *  [a-zA-Z]    a through z or A through Z. 
     * 
     *  (\\d+\\.\\d+)|(\\d+)  This regex will match an integer or a number containing the decimal separator "." e.g. 0.45
     * 
     */
    public void createRP() {
        String s;
        try {
            // brCount is used to decide how big array should be
            BufferedReader brCount = new BufferedReader(new FileReader(file));
            int arraySize = 0;
            String rpRegex = "\\s+\\d+\\s+\\d+\\s+\\d\\.\\d+";
            Pattern RPpattern = Pattern.compile(rpRegex);
            while ((s = brCount.readLine()) != null) {
                Matcher RPmatcher = RPpattern.matcher(s);
                if (RPmatcher.find()) {
                    ++arraySize;
                }
            }
            baseSequence = new String[arraySize];
            knotSequence = new String[arraySize];
            shapeReactivity = new double[arraySize];
            BufferedReader br = new BufferedReader(new FileReader(file));
            while ((s = br.readLine()) != null) {
                if (validateRP(s)) {
                    Pattern pattern = Pattern.compile("(\\d+\\.\\d+)|(\\d+)");
                    Matcher matcher = pattern.matcher(s);
                    matcher.find();
                    int indexNuc1Knot = Integer.parseInt(matcher.group());
                    matcher.find();
                    int indexNuc2Knot = Integer.parseInt(matcher.group());
                    matcher.find();
                    double shapeValue = Double.parseDouble(matcher.group());
                    // base is always set to the number of the first nuc as there are no nucs in this data format
                    // String base = "" + indexNuc1Knot;
                    // As of now all bases are set to "A"
                    String base = "A";
                    baseSequence[indexNuc1Knot - 1] = base;
                    shapeReactivity[indexNuc1Knot - 1] = shapeValue;
                    if (indexNuc2Knot == 0) {
                        knotSequence[indexNuc1Knot - 1] = ":";
                    }
                    if (indexNuc1Knot < indexNuc2Knot) {
                        knotSequence[indexNuc1Knot - 1] = "(";
                        knotSequence[indexNuc2Knot - 1] = ")";
                    }
                } else {
                    //if validation fails
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(LoadFile.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Error: " + ex.getMessage());
        }
    }

    /**
     * 
     */
    public void createReactivity() {
        String s;
        try {
            // brCount is used to decide how big array should be
            BufferedReader brCount = new BufferedReader(new FileReader(file));
            int arraySize = 0;
            String rpRegex = "\\s+\\d+\\s+\\d+\\s+\\d\\.\\d+";
            Pattern RPpattern = Pattern.compile(rpRegex);
            while ((s = brCount.readLine()) != null) {
                Matcher RPmatcher = RPpattern.matcher(s);
                if (RPmatcher.find()) {
                    ++arraySize;
                }
            }
            baseSequence = new String[arraySize];
            knotSequence = new String[arraySize];
            shapeReactivity = new double[arraySize];
            BufferedReader br = new BufferedReader(new FileReader(file));
            while ((s = br.readLine()) != null) {
                if (validateRP(s)) {
                    Pattern pattern = Pattern.compile("(\\d+\\.\\d+)|(\\d+)");
                    Matcher matcher = pattern.matcher(s);
                    matcher.find();
                    int indexNuc1Knot = Integer.parseInt(matcher.group());
                    matcher.find();
                    int indexNuc2Knot = Integer.parseInt(matcher.group());
                    matcher.find();
                    double shapeValue = Double.parseDouble(matcher.group());
                    // base is always set to the number of the first nuc as there are no nucs in this data format
                    // String base = "" + indexNuc1Knot;
                    // As of now all bases are set to "A"
                    String base = "A";
                    baseSequence[indexNuc1Knot - 1] = base;
                    shapeReactivity[indexNuc1Knot - 1] = shapeValue;
                    if (indexNuc2Knot == 0) {
                        knotSequence[indexNuc1Knot - 1] = ":";
                    }
                    if (indexNuc1Knot < indexNuc2Knot) {
                        knotSequence[indexNuc1Knot - 1] = "(";
                        knotSequence[indexNuc2Knot - 1] = ")";
                    }
                } else {
                    //if validation fails
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(LoadFile.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Error: " + ex.getMessage());
        }
    }

    /**
     * 
     * @param s
     * @returns always boolean true. Not yet implemented.
     */
    public boolean validateDotbracket(String s) {
        //not yet implemented
        return true;
    }

    /**
     * 
     * @param s
     * @return true if string is found matching regular expression \\d+\\s+[A-Za-z]\\s+\\d+\\s+\\d+\\s+\\d+
     * 
     *  \d          A digit: [0-9]
     *  \s          A whitespace character
     *  +           The preceding is repeated one or more times.
     *  [a-zA-Z]    a through z or A through Z. 
     * 
     */
    public boolean validateCT(String s) {
        String ctRegex = "\\d+\\s+[A-Za-z]\\s+\\d+\\s+\\d+\\s+\\d+";
        Pattern BPSEQpattern = Pattern.compile(ctRegex);
        Matcher BPSEQmatcher = BPSEQpattern.matcher(s);
        return BPSEQmatcher.find();
    }

    /**
     * 
     * @param s
     * @return true if string is found matching regular expression \\d+\\s+[A-Za-z]\\s+\\d+
     * 
     *  \d          A digit: [0-9]
     *  \s          A whitespace character
     *  +           The preceding is repeated one or more times.
     *  [a-zA-Z]    a through z or A through Z. 
     * 
     */
    public boolean validateBPSEQ(String s) {
        String bpseqRegex = "\\d+\\s+[A-Za-z]\\s+\\d+";
        Pattern BPSEQpattern = Pattern.compile(bpseqRegex);
        Matcher BPSEQmatcher = BPSEQpattern.matcher(s);
        return BPSEQmatcher.find();
    }

    /**
     * 
     * @param s
     * @return true if string is found matching regular expression \\s+\\d+\\s+\\d+\\s+\\d\\.\\d+
     *  \d          A digit: [0-9]
     *  \s          A whitespace character
     *  +           The preceding is repeated one or more times.
     *  .           Matches any character
     */
    public boolean validateRP(String s) {
        String rpRegex = "\\s+\\d+\\s+\\d+\\s+\\d\\.\\d+";
        Pattern rpPattern = Pattern.compile(rpRegex);
        Matcher rpMatcher = rpPattern.matcher(s);
        return rpMatcher.find();
    }
}
